package controle;

import java.lang.Math;

import modelo.Ponto;

//Internal matrix element organization reference
//          [ matrix[0] matrix[4] matrix[8]  matrix[12] ]
//Transform = [ matrix[1] matrix[5] matrix[9]  matrix[13] ]
//          [ matrix[2] matrix[6] matrix[10] matrix[14] ]
//          [ matrix[3] matrix[7] matrix[11] matrix[15] ]

/**
 * Classe que representa a matriz de transformação. Possui operações como
 * translação, rotação e escala
 * 
 * @author jean
 * @author diego
 */
public final class Transformacao {
	/**
	 * 
	 */
	public static final double RAS_DEG_TO_RAD = 0.017453292519943295769236907684886;

	/**
	 * matriz de 16 posições
	 */
	private double[] matrix = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};

	/**
	 * Cria a representação da matriz de transformação
	 */
	public Transformacao() {

	}

	/**
	 * Faz a matriz identidade
	 */
	public void makeIdentity() {
		for (int i = 0; i < 16; ++i) {
			matrix[i] = 0.0;
			matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0;
		}
	}

	/**
	 * Faz a matriz de translação<br>
	 * 0 0 0 0<br>
	 * 0 0 0 0<br>
	 * 0 0 0 0<br>
	 * X Y Z 0
	 * 
	 * @param translationVector
	 */
	public void makeTranslation(Ponto translationVector) {
		makeIdentity();
		matrix[12] = translationVector.getX();
		matrix[13] = translationVector.getY();
		matrix[14] = translationVector.getZ();
	}

	/**
	 * Faz rotação no eixo X
	 * 
	 * @param radians
	 */
	public void makeXRotation(double radians) {
		makeIdentity();
		matrix[5] = Math.cos(radians);
		matrix[9] = -Math.sin(radians);
		matrix[6] = Math.sin(radians);
		matrix[10] = Math.cos(radians);
	}

	/**
	 * Faz rotação no eixo y
	 * 
	 * @param radians
	 */
	public void makeYRotation(double radians) {
		makeIdentity();
		matrix[0] = Math.cos(radians);
		matrix[8] = Math.sin(radians);
		matrix[2] = -Math.sin(radians);
		matrix[10] = Math.cos(radians);
	}

	/**
	 * Faz rotação no eio z
	 * 
	 * @param radians
	 */
	public void makeZRotation(double radians) {
		makeIdentity();
		matrix[0] = Math.cos(radians);
		matrix[4] = -Math.sin(radians);
		matrix[1] = Math.sin(radians);
		matrix[5] = Math.cos(radians);
	}

	/**
	 * Faz Transformação em scala
	 * 
	 * @param sX
	 * @param sY
	 * @param sZ
	 */
	public void makeScale(double sX, double sY, double sZ) {
		makeIdentity();
		matrix[0] = sX;
		matrix[5] = sY;
		matrix[10] = sZ;
	}

	/**
	 * @param ponto
	 * @return - o ponto
	 */
	public Ponto transformPonto(Ponto ponto) {
		Ponto PontoResult = new Ponto(matrix[0] * ponto.getX() + matrix[4]
				* ponto.getY() + matrix[8] * ponto.getZ() + matrix[12]
				* ponto.getW(), matrix[1] * ponto.getX() + matrix[5]
				* ponto.getY() + matrix[9] * ponto.getZ() + matrix[13]
				* ponto.getW(), matrix[2] * ponto.getX() + matrix[6]
				* ponto.getY() + matrix[10] * ponto.getZ() + matrix[14]
				* ponto.getW(), matrix[3] * ponto.getX() + matrix[7]
				* ponto.getY() + matrix[11] * ponto.getZ() + matrix[15]
				* ponto.getW());
		return PontoResult;
	}

	/**
	 * @param t
	 *            - a matriz de transformação
	 * @return a matriz tranasformada
	 */
	public Transformacao transformMatrix(Transformacao t) {
		Transformacao result = new Transformacao();
		for (int i = 0; i < 16; ++i)
			result.matrix[i] = matrix[i % 4] * t.matrix[i / 4 * 4]
					+ matrix[(i % 4) + 4] * t.matrix[i / 4 * 4 + 1]
					+ matrix[(i % 4) + 8] * t.matrix[i / 4 * 4 + 2]
					+ matrix[(i % 4) + 12] * t.matrix[i / 4 * 4 + 3];
		return result;
	}

	/**
	 * Retorna o elemento que está na posição informada
	 * 
	 * @param index
	 *            - a posição do elemento
	 * @return o elemento que está na posição informada
	 */
	public double getElement(int index) {
		return matrix[index];
	}

	/**
	 * @param index
	 * @param value
	 */
	public void setElement(int index, double value) {
		matrix[index] = value;
	}

	/**
	 * @return a matriz
	 */
	public double[] getDate() {
		return matrix;
	}

	/**
	 * @param data
	 */
	public void setData(double[] data) {
		int i;

		for (i = 0; i < 16; i++) {
			matrix[i] = (data[i]);
		}
	}

}
